package com.xishu.client;

import com.xishu.config.Config;
import com.xishu.util.Tools;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.retry.RetryNTimes;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * zk客户端
 */
public class ZkClient implements Tools {
    private static Logger logger = LoggerFactory.getLogger(ZkClient.class);
    private static ZkClient instance = new ZkClient();
    private CuratorFramework client;
    Config config = Config.getInstance();

    private ZkClient() {

        try {
            client = CuratorFrameworkFactory.newClient(config.getZkServer() + ":" + config.getZkPort(), new RetryNTimes(10, 5000));
            client.start();
        } catch (Exception e) {
            logger.error("e", e);
        }
    }

    /**
     * 创建一个客户端
     *
     * @return
     */
    public static CuratorFramework createClient() {
        Config config = Config.getInstance();
        CuratorFramework client = CuratorFrameworkFactory.newClient(config.getZkServer() + ":" + config.getZkPort(), new RetryNTimes(10, 5000));
        client.start();
        return client;
    }

    public static ZkClient getInstance() {
        return instance;
    }

    /**
     * 获取ZK CLIENT
     *
     * @return
     */
    public synchronized CuratorFramework getClient() {
//        long startTime = System.currentTimeMillis();
//        client = CuratorFrameworkFactory.newClient(config.getZkServer() + ":" + config.getZkPort(), new RetryNTimes(10, 5000));
//        client.start();
//        logger.info("start client cost time {}", System.currentTimeMillis() - startTime);
//        return client;

        if (client == null) {
            RetryPolicy retry = new ExponentialBackoffRetry(1000, 3);
            client = CuratorFrameworkFactory.newClient(config.getZkServer() + ":" + config.getZkPort(), 60000, 15000, retry);
//            client = CuratorFrameworkFactory.newClient(config.getZkServer() + ":" + config.getZkPort(), new RetryNTimes(10, 5000));
            client.start();
        }

        return client;
    }

    /**
     * 创建持久节点
     */
    public void createPersistNode(String path, String data) throws Exception {
        logger.info("create persist node {} value {}", path, data);
        client.create().creatingParentsIfNeeded().forPath(path, data.getBytes());
    }

    /**
     * 判断节点是否存在
     *
     * @param path
     * @return
     */
    public boolean isPathExist(String path) throws Exception {
        Stat stat = client.checkExists().forPath(path);
        return stat != null;
    }

    /**
     * ls
     *
     * @param path
     */
    public void ls(String path) throws Exception {
        client.getData().forPath(path);
    }

    /**
     * 获取数据节点的值
     *
     * @param
     */
    public String getData(String path) throws Exception {
        return new String(client.getData().forPath(path));
    }

    /**
     * 获取数据节点数值的值，如果没有，则添加默认值
     *
     * @param path
     * @param defaultData
     * @return
     */
    public String getData(String path, String defaultData) throws Exception {
        byte[] bytes = null;

        try {
            bytes = client.getData().forPath(path);
        } catch (Exception e) {
            logger.error("e", e);

            if (!isPathExist(path)) {
                createPersistNode(path, defaultData);
                return defaultData;
            }

            setData(path, defaultData);
            return defaultData;
        }

        if (bytes == null || bytes.length == 0) {
            setData(path, defaultData);
            return defaultData;
        }

        return new String(bytes);
    }

    /**
     * 设置值
     *
     * @param path
     * @param data
     */
    public void setData(String path, String data) throws Exception {
        client.setData().forPath(path, data.getBytes());
    }

    /**
     * 设置值
     *
     * @param path
     * @param data
     */
    public void setData(String path, Object data) throws Exception {
        client.setData().forPath(path, data.toString().getBytes());
    }

    /**
     * 添加一个数字，返回添加之后的数字
     *
     * @param path
     * @param defaultNumber
     * @throws Exception
     */
    public synchronized int addNumber(String path, int defaultNumber) throws Exception {
        if (!isPathExist(path)) {
            createPersistNode(path, String.valueOf(defaultNumber));
        }

        //在现有基础上加1，再写进入
        String data = getData(path);

        int uniqueCode = 0;

        try {
            uniqueCode = Integer.parseInt(data) + 1;
        } catch (Exception e) {
            uniqueCode = 1;
        }

        logger.info("add the path {} number {}", path, uniqueCode);
        setData(path, uniqueCode);
        return uniqueCode;
    }


}
